package com.zlyx.easy.security.authentication.aspect;

import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;

import com.zlyx.easy.core.map.EasyMap;
import com.zlyx.easy.core.utils.MethodUtils;
import com.zlyx.easy.core.utils.RequestUtils;
import com.zlyx.easy.core.utils.StringUtils;

/**
 * <p>
 * token过期时间重置切面
 * </p>
 *
 * @author 赵光
 * @version v1.0
 */
@Component
@Aspect
public class TokenAspect {

	private Logger logger = LoggerFactory.getLogger(TokenAspect.class);

	@Autowired
	private TokenStore tokenStore;

	@Around("@annotation(requestMapping)")
	public Object doAround(ProceedingJoinPoint pjp, RequestMapping requestMapping) throws Throwable {
		Method targetMethod = ((MethodSignature) pjp.getSignature()).getMethod();
		Class<?> realClass = targetMethod.getDeclaringClass();
		if (realClass.isInterface()) {
			logger.debug("feign is ignore");
			return pjp.proceed();
		}
		HttpServletRequest request = RequestUtils.getRequest();
		if (request == null) {
			logger.debug("request is null");
			return pjp.proceed();
		}
		String url = request.getRequestURI();
		if (StringUtils.equals("/oauth/check_token", url)) {
			Method realMethod = MethodUtils.getRealMethod(realClass, targetMethod);
			EasyMap<String, Object> params = MethodUtils.getParamsMap(realMethod, pjp.getArgs());
			String token = params.getString("value");
			DefaultOAuth2AccessToken accessToken = (DefaultOAuth2AccessToken) tokenStore.readAccessToken(token);
			if (accessToken == null) {
				logger.debug("token = {} is expired", token);
				return pjp.proceed();
			}
			ZonedDateTime zdt = LocalDateTime.now().plusHours(24).atZone(ZoneId.systemDefault());
			accessToken.setExpiration(Date.from(zdt.toInstant()));
			OAuth2Authentication authentication = tokenStore.readAuthentication(token);
			tokenStore.storeAccessToken(accessToken, authentication);
			logger.debug("token = {}, principal = {} is refreshed", token, authentication.getPrincipal());
		}
		return pjp.proceed();
	}
}